#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <event2/bufferevent.h>
#include <event2/event.h>
#include <arpa/inet.h>

// 6.接受、发送数据bufferevent_read() / bufferevent_write()
// 写缓冲区回调
void read_cb(struct bufferevent *bev, void *arg){
    char buf[1024] = { 0 };
    bufferevent_read(bev, buf, sizeof(buf)); 

    printf("server say:%s\n", buf);

    bufferevent_write(bev, buf, strlen(buf) + 1);

    sleep(1);
    return;
}

// 读缓冲区回调
void write_cb(struct bufferevent *bev, void *arg){
    printf("----------我是客户端的写回调函数,没卵用哦\n");
}

// 事件回调
void event_cb(struct bufferevent *bev, short events, void *arg){
    if(events & BEV_EVENT_EOF){
        printf("connection closed\n");
    }
    else if(events & BEV_EVENT_ERROR){
        printf("some other error\n");
    }
    else if(events & BEV_EVENT_CONNECTED){
        printf("已经连接服务器...\n");
        return;
    }

    bufferevent_free(bev);
    printf("buffevent 资源已经被释放...\n");
}

// 客户端与用户交互，从终端读取数据写给服务器
void read_terminal(evutil_socket_t fd, short what, void *arg){
    // 读数据
    char buf[1024] = { 0 };

    // 读的是标准输入, 不是bufferevent缓冲区
    int len = read(fd, buf, sizeof(buf));
    struct bufferevent* bev = (struct bufferevent*)arg; 

    // 发送给服务器bufferevent缓冲区
    bufferevent_write(bev, buf, len + 1);  
    return;
}

int main(int argc, char *argv[]){
    // 1.创建event_base
    struct event_base *base;
    base = event_base_new();

    int fd = socket(AF_INET, SOCK_STREAM, 0);

    // 2.使用bufferevent_socket_new()创建一个用跟服务器通信的bufferevent事件对象
    struct bufferevent *bev;
    bev = bufferevent_socket_new(base, fd, BEV_OPT_CLOSE_ON_FREE);

    // init server info
    struct sockaddr_in serv;
    memset(&serv, 0, sizeof(serv));
    serv.sin_family = AF_INET;
    serv.sin_port = htons(9876);
    serv.sin_addr.s_addr = htonl(INADDR_ANY);

    // 3.使用bufferevent_socket_connect()连接服务器
    bufferevent_socket_connect(bev, (struct sockaddr*)&serv, sizeof(serv));

    // 4.使用bufferevent_setcb()给这个事件对象的read、write、event设置回调
    bufferevent_setcb(bev, read_cb, write_cb, event_cb, NULL);

    // 5.设置读回调生效
    //bufferevent_enable(bev, EV_READ);

    // 创建event事件 (不使用bufferevent缓存区读写)
    struct event *ev = event_new(base, STDIN_FILENO, EV_READ | EV_PERSIST, read_terminal, bev);

    // 添加事件
    event_add(ev, NULL);

    // 7.循环监听
    event_base_dispatch(base);
    
    // 8.释放资源
    event_free(ev);
    event_base_free(base);
    
    return 0;
}